//
//  main.cpp
//  Parse
//
//  Created by Benson Tran on 5/21/13.
//  Copyright (c) 2013 Benson Tran. All rights reserved.
//

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

#define SC_NUM 14
#define SC_LENGTH 3101
#define PAT_NUM 1528

struct pattern{
    char scan_in[SC_NUM][SC_LENGTH];
    char scan_out[SC_NUM][SC_LENGTH];
    
    // Used for analyse_pattern
    int  si_left;
    int  si_right;
    int  so_left;
    int  so_right;
    
};

int min(int a, int b) {
	if (a<b) return a;
	else return b;
}

int count_overlap(pattern * pat[]) {
	int overlap = 0;
	for(int i = 0; i < PAT_NUM-1; i++) {
		overlap = overlap + min(pat[i]->si_right, pat[i+1]->so_left);
	}
	return overlap;
}


void analyse_pattern(pattern * pat[]){
    
    for(int i = 0; i < PAT_NUM; i++){
        
        int si_left_keep  = 9999;
        int si_right_keep = 9999;
        int so_left_keep  = 9999;
        int so_right_keep = 9999;
        
        for(int j = 0; j < SC_NUM; j++){
            
            int si_left_counter  = 0;
            int si_right_counter = 0;
            int so_left_counter  = 0;
            int so_right_counter = 0;
            
            // Check scan_in left length
            
            int k = 0;
            
            while(pat[i]->scan_in[j][k] == 'N'){
                si_left_counter ++;
                k++;
            }
            
            if(si_left_counter < si_left_keep) {
                si_left_keep = si_left_counter;
            }
            
            // Check scan_in right length
            
            k = 0;
            
            while(pat[i]->scan_in[j][SC_LENGTH-1-k] == 'N'){
                si_right_counter ++;
                k++;
            }
            
            if(si_right_counter < si_right_keep) {
                si_right_keep = si_right_counter;
            }
            
            // Check scan_out left length
            
            k = 0;
            
            while(pat[i]->scan_out[j][k] == 'N'){
                so_left_counter ++;
                k++;
            }
            
            if(so_left_counter < so_left_keep) {
                so_left_keep = so_left_counter;
            }
            
            
            // Check scan_out right length
            
            k = 0;
            
            while(pat[i]->scan_out[j][SC_LENGTH-1-k] == 'N'){
                so_right_counter ++;
                k++;
            }
            
            if(so_right_counter < so_right_keep) {
                so_right_keep = so_right_counter;
            }
            
        }
        
        // Add values to pattern struct.
        
        pat[i]->si_left = si_left_keep;
        pat[i]->si_right = si_right_keep;
        pat[i]->so_left = so_left_keep;
        pat[i]->so_right = so_right_keep;
        
    }
}




int transpose(pattern * pat[], const char* scan_in_file, const char* scan_out_file){
    
    ofstream myfile;
    myfile.open(scan_out_file);
        
    for(int i = 0; i < PAT_NUM; i++){
        myfile << "// Pattern_" << i << "\n" << "\n";
        for(int j = 0; j < SC_LENGTH; j++){
            for(int k = 0; k < SC_NUM; k++){
            	switch(pat[i]->scan_out[k][j]) {
            		case 'X':
            			myfile << 'X';
						break;
					case 'L':
						myfile << '0';
						break;
					case 'H':
						myfile << '1';
						break;
					default:
						cout << "Error: unknown symbol in scan_out data: " << pat[i]->scan_out[k][j] << ". Exiting" << endl;
						return 1;
					}
            }
            myfile << endl;
        }
    }
    
    myfile.close();
    
    ofstream myFile;
    myFile.open(scan_in_file);
    
    for(int i = 0; i < PAT_NUM; i++){
        myFile << "// Pattern_" << i << endl;
        for(int j = 0; j < SC_LENGTH; j++){
            for(int k = 0; k < SC_NUM; k++){
            	switch(pat[i]->scan_in[k][j]) {
            	case 'N':
            		myFile << '0';
            		break;
            	case '0':
            		myFile << '0';
            		break;
            	case '1':
            		myFile << '1';
            		break;
            	default:
            		cout << "Error: unknown symbol in scan_in data: pat["<<i<<"]->scan_in["<<k<<"]["<<j<<"]=" << pat[i]->scan_in[k][j] << ". Exiting" << endl;
            		return 1;
            	}
                //myFile << pat[i]->scan_in[k][j];
            }
            myFile << endl;
        }
    }
    
    myFile.close();
    return 0;
}

void results(pattern * pattern_array[]){
    
    ofstream myfile;
    myfile.open ("results.txt");
    
    for(int i = 0; i < PAT_NUM; i++){
        myfile << "Pattern " << i << ": \n" << "\n";
        for(int j = 0; j < SC_NUM; j++){ // Write scan_ins to file
            myfile << "scan_in" << j+1 << ": ";
            for(int k = 0; k < SC_LENGTH; k++){
                myfile << pattern_array[i]->scan_in[j][k];
            }
            myfile << "\n" << "\n";
        }
        
        for(int j = 0; j < SC_NUM; j++){ // Write scan_outs to file
            myfile << "scan_out" << j+1 << ": ";
            for(int k = 0; k < SC_LENGTH; k++){
                myfile << pattern_array[i]->scan_out[j][k];
            }
            myfile << "\n" << "\n";
        }
        myfile << "\n" << "\n";
    }
    
    for(int i = 0; i < PAT_NUM; i++){
        
        myfile << "Pattern " << i << " si_left = " << pattern_array[i]->si_left << "\n";
        myfile << "Pattern " << i << " si_right = " << pattern_array[i]->si_right << "\n";
        myfile << "Pattern " << i << " so_left = " << pattern_array[i]->so_left << "\n";
        myfile << "Pattern " << i << " so_right = " << pattern_array[i]->so_right << "\n" << "\n";
    }
    
    myfile.close();
    
}


int main(int argc, const char * argv[])
{
	if (argc !=4) {
		cout << "Error: 3 arguments required: <stil_file> <scan_ins> <scan_outs>" << endl << "Exiting." << endl;
		return 1;
	}
    const char* stil_file = argv[1];
    const char* scan_in_file = argv[2];
    const char* scan_out_file = argv[3];
    // Part 1
    
    pattern* pattern_array[PAT_NUM]; // Create pattern array.
    for (int i = 0; i < PAT_NUM; i++) {
        pattern_array[i] = new pattern;
    }
    
    string data; // Serves as the string buffer for getline()
    char temp = 0; // Serves as char buffer.
    
    
    ifstream file (stil_file); // stil.txt file
    
    if (!file.is_open()) {
        
    	cout << "Error opening file" << endl;
    	return -1;
        
    }
    
    int linecounter = 0; // Used for finding which line there is an error in the number of characters (i.e. < 3101)
    int lineadder;
    if(SC_LENGTH % 1024 != 0){
        
            lineadder = SC_LENGTH / 1024 + 1 + 1; // Used to increase line count after scan_ins/scan_outs/pis/pos (+1 for extra 'paragraph +1 for ;)
    }
    
    else{
        
        lineadder = SC_LENGTH / 1024 + 1; // +1 for ;
    }

    
    while(!file.eof()){
        
        getline(file, data, '\r'); // Consistently moves pointer until "scan_in1"=.
        linecounter ++;
        long pos = data.find("\"scan_in1\"="); // Tells me whether "scan_in1=" exists in the data stream. -1 if doesnt.

        
        if(pos != -1){
            // cout << linecounter; // What line the first scan_in1 is located.
            
            for(int i = 0; i < SC_LENGTH; i++){ // Put first scan_in1 data in pattern array
                file >> pattern_array[0]->scan_in[0][i];
            }
            
            file >> temp;
            // cout << temp << endl; // Outputs ; // Use ";" as checker as to whether 3101 character's were read in.
            
            if(temp != ';'){
                cout << "Error: There aren't " << SC_LENGTH << " characters from scan_in" << 1 << " on line " << linecounter << "." << endl;
                cout << "Program Terminated." << endl;
                return -1;
            }
            
            linecounter = linecounter + lineadder;

            
            for(int k = 0; k <= PAT_NUM; k ++){ // Go through each pattern
                if(k > 0){ // Already read in all pattern 1s "scan_in"'s
                    
                    // Get rid of po and pi data.
                    int equalsigncounter = 0; // Needs to equal 3
                    
                    while(equalsigncounter != 3){
                        temp = file.get();
                        if(temp == '='){
                            equalsigncounter ++;
                        }
                        else if(temp == '\n'){
                            linecounter ++;
                        }

                    }
                    
                    // Get scan_out data
                    for(int i = 0; i < SC_NUM; i++){
                        for(int j = 0; j < SC_LENGTH; j++){ // Put scan_out data in pattern array
                            file >> temp;
                            pattern_array[k-1]->scan_out[i][j] = temp;
                        }
                        
                        // Next lines of code is to move pointer.
                        file >> temp;
                        // cout << temp << endl; // Outputs ;
                        
                        if(temp != ';'){
                            cout << "Error: There aren't " << SC_LENGTH << " characters from scan_out" << i+1 << " on line " << linecounter << "." << endl;
                            cout << "Program Terminated." << endl;
                            return -1;
                        }
                        
                        linecounter = linecounter + lineadder;
                        
                        while(temp != '='){
                            temp = file.get();
                            if(temp == '\n'){
                                linecounter ++;
                            }
                            
                        }
                        
                    }
                    // Get scan_in data
                    for(int i = 0; i < SC_NUM; i++){
                        for(int j = 0; j < SC_LENGTH; j++){ // Put scan_in data in pattern array.
                            
                            file >> temp;
                            if(k != PAT_NUM){ // Discard last scan_in.
                                pattern_array[k]->scan_in[i][j] = temp;
                            }
                            
                        }
                        // Next lines of code is to move pointer.
                        file >> temp;
                        // cout << temp << endl; // Outputs ;
                        
                        if(temp != ';'){
                            cout << "Error: There aren't " << SC_LENGTH << " characters from scan_in" << i+1 << " on line " << linecounter << "." << endl;
                            cout << "Program Terminated." << endl;
                            return -1;
                        }
                        
                        linecounter = linecounter + lineadder;
                        
                        if(i != SC_NUM - 1){
                            while(temp != '='){
                                temp = file.get();
                                if(temp == '\n'){
                                    linecounter ++;
                                }
                            }
                        }

                    }
                    
                }
                
                else{ // Read in the first set of scan_ins
                    for(int i = 1; i < SC_NUM; i++){
                        // Move pointer all the way until the equal sign.
            
                        while(temp != '='){
                            temp = file.get();
                           // cout << temp;
                            if(temp == '\n')
                                linecounter ++;
                              //  cout << linecounter << endl;
                        }

                        // Go to next scan_in.
                        
                        for(int j = 0; j < SC_LENGTH; j++){
                            file >> pattern_array[k]->scan_in[i][j];
                        }
                        
                        file >> temp;
                        // cout << temp << endl; // Outputs ; // Use ";" as checker as to whether 3101 character's were read in.
                        
                        if(temp != ';'){
                            cout << "Error: There aren't " << SC_LENGTH << " characters from scan_in" << i+1 << " on line " << linecounter << "." << endl;
                            cout << "Program Terminated." << endl;
                            return -1;
                        }
                        

                            linecounter = linecounter + lineadder;
                        

                    }
                    
                }
                
                
            }
            
        }
        
    }
    
    file.close();
    
    // Run part 2
    
    analyse_pattern(pattern_array);
    
    // Run part 3
    
    transpose(pattern_array, scan_in_file, scan_out_file);
    
    // Next line of code is used to output results for part 1 and 2.
    
    results(pattern_array);
    
    cout<< "count overlap = " << count_overlap(pattern_array)<< endl;

    
    return 0;
    
    
    
}

